﻿#region Imports
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using CommonUtilities.Attributes;
using CommonUtilities.Commands;
using CommonUtilities.Enums;
using CommonUtilities.Extensions;
using CommonUtilities.Messages;
using CommonUtilities.Util;
using OneStopProgrammingMatrix.Cache;
using OneStopProgrammingMatrix.Common;
using OneStopProgrammingMatrix.Models;
#endregion

namespace OneStopProgrammingMatrix.ViewModels
{
    public class AddNewItemViewModel : BaseViewModel
    {
        #region Declarations
        bool wrongGroupEntryCancelledRKD = false;
        #endregion Declarations

        #region Properties
        private MatrixItem newItem;
        public MatrixItem NewItem
        {
            get { return newItem; }
            set { newItem = value; RaisePropertyChanged("NewItem"); }
        }

        private ObservableCollection<string> allGroups;
        public ObservableCollection<string> AllGroups
        {
            get { return allGroups; }
            set { allGroups = value; RaisePropertyChanged("AllGroups"); }
        }

        private string selectedGroup;
        public string SelectedGroup
        {
            get { return selectedGroup; }
            set
            {
                selectedGroup = value; RaisePropertyChanged("SelectedGroup");
                NewItem.Coalesce(new MatrixItem()).MatrixGroup = SelectedGroup;
            }
        }

        private bool isGroupSelectionEnabled;
        public bool IsGroupSelectionEnabled
        {
            get { return isGroupSelectionEnabled; }
            set { isGroupSelectionEnabled = value; RaisePropertyChanged("IsGroupSelectionEnabled"); }
        }

        private MatrixItem selectedMatrixItem;
        public MatrixItem SelectedMatrixItem
        {
            get { return selectedMatrixItem; }
            set
            {
                selectedMatrixItem = value; RaisePropertyChanged("SelectedMatrixItem");
                ClearNewItemFields(SelectedMatrixItem);
            }
        }

        private ObservableCollection<MatrixItem> allMatrixItems;
        public ObservableCollection<MatrixItem> AllMatrixItems
        {
            get { return allMatrixItems; }
            set { allMatrixItems = value; RaisePropertyChanged("AllMatrixItems"); }
        }

        private bool isEditMode;
        public bool IsEditMode
        {
            get { return isEditMode; }
            set { isEditMode = value; RaisePropertyChanged("IsEditMode"); }
        }

        private eUpdateMode updateMode;
        public eUpdateMode UpdateMode
        {
            get { return updateMode; }
            set { updateMode = value; RaisePropertyChanged("UpdateMode"); }
        }

        public RelayCommand<MatrixItem> AddEditMatrixItemCommand { get; private set; }
        public RelayCommand DeleteCommand { get; private set; }
        public RelayCommand CancelCommand { get; private set; }
        public RelayCommand BrowsePathCommand { get; private set; }
        #endregion Properties

        #region Constructors
        public AddNewItemViewModel()
        {
            InitializeCommands();
        }
        #endregion Constructors

        private void InitializeCommands()
        {
            AddEditMatrixItemCommand = new RelayCommand<MatrixItem>((parameter) =>
            {
                string sFaultFields = "";
                if (ValidateNewItem(ref sFaultFields))
                {
                    switch (UpdateMode)
                    {
                        case eUpdateMode.Edit:
                            if (!NewItem.IsNull())
                            {
                                var items = DataCache.DBMatrixItems;
                                if (items.Remove(items._Where(d => d.PKey == NewItem.PKey && NewItem.PKey != new Guid()).First()))
                                    items.Add(NewItem);

                                DataCache.WriteMatrix(items);
                            }
                            break;

                        case eUpdateMode.Add:
                        default:
                            AddNewItemCommand_Execute_OnAdd(null);
                            break;
                    }

                    if (!wrongGroupEntryCancelledRKD)
                    {
                        if (MessageBox.Show("Close?", "Confirmation", MessageBoxButtons.YesNo) == DialogResult.Yes)
                            CancelCommand.Execute(true);
                        else ClearNewItemFields(new MatrixItem());
                    }
                }
                else MessageBox.Show("Please fill the mandatory field(s) : " + sFaultFields, "Validation..");
            });

            DeleteCommand = new RelayCommand((parameter) =>
            {
                if (!NewItem.IsNull())
                {
                    var items = DataCache.DBMatrixItems;
                    if (items.Remove(items._Where(d => d.PKey == NewItem.PKey && NewItem.PKey != new Guid()).First()))
                    {
                        DataCache.WriteMatrix(items);
                        CancelCommand.Execute(true);
                    }
                }
            });

            CancelCommand = new RelayCommand((parameter) =>
            {
                SelectedGroup = null; NewItem = null;
                EventNotifier.CancelAddNewItemCommand.Execute(parameter.Coalesce(false));
            });
            // CancelCommand = new RelayCommand<object>((parameter) =>{  EventNotifier.AddNewItemClosed(null, null);}); //RKD : alternate event call

            EventNotifier.RefreshNewItemWindowCommand = new RelayCommand<eUpdateMode>((parameter) =>
                {
                    ObservableCollection<string> allGroups = DataCache.DBMatrixItems
                        ._OrderBy(itm => itm.MatrixGroup)._Select(itm => itm.MatrixGroup).Distinct().ToObservableCollection();
                    allGroups.Insert(0, String.Empty);
                    AllGroups = allGroups;

                    UpdateMode = parameter;
                    IsEditMode = (UpdateMode == eUpdateMode.Edit);

                    switch (UpdateMode)
                    {
                        case eUpdateMode.Edit:
                            AllMatrixItems = DataCache.DBMatrixItems;
                            SelectedMatrixItem = null;
                            ClearNewItemFields(SelectedMatrixItem);
                            break;

                        case eUpdateMode.Add:
                        default:
                            ClearNewItemFields(new MatrixItem()); break;
                    }
                });

            EventNotifier.NewItemMatrixGroupChangedCommand = new RelayCommand<object>((parameter) =>
                {
                    IsGroupSelectionEnabled = (NewItem.Coalesce(new MatrixItem()).MatrixGroup.IsBlank() || SelectedGroup.IsNull()
                        || NewItem.MatrixGroup == "<Enter group>" // RKD : handle waterark (use property or bind with wmark)
                        || NewItem.MatrixGroup == SelectedGroup);
                });

            BrowsePathCommand = new RelayCommand((parameter) =>
            {
                var dlg = DialogInitializers.Create_OpenFileDialog(
                    title: "Select file..", defaultExt: "exe", filter: "Applications (*.exe)|*.exe",
                    initialDirectory: NewItem.Path.GetDirectoryNameFull(), fileName: Path.GetFileName(NewItem.Path));
                var dr = dlg.ShowDialog();
                if (dr == DialogResult.OK) { NewItem.Path = dlg.FileName; NewItem.Name = Path.GetFileNameWithoutExtension(dlg.FileName).CapitalizeEachWord(); }
            });
        }

        private void AddNewItemCommand_Execute_OnAdd(object parameter)
        {
            if (NewItem.MatrixGroup.IsBlank())
            {
                if (MessageBoxUtil.Show(Debugger.IsAttached, "Continue without a group?", "Confirmation..", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.No)
                {
                    wrongGroupEntryCancelledRKD = true;
                    return;
                }
            }

            var matrixItems = DataCache.DBMatrixItems;

            matrixItems.Add(new MatrixItem
                {
                    MatrixGroup = NewItem.MatrixGroup, // NewGroup.Coalesce(SelectedGroup),
                    Name = NewItem.Name,
                    Description = NewItem.Description,
                    Path = NewItem.Path
                });

            wrongGroupEntryCancelledRKD = false;
            DataCache.WriteMatrix(matrixItems);
        }

        private bool ValidateNewItem(ref string sFaultFields)
        {
            bool result = true;
            ObservableCollection<string> faults = new ObservableCollection<string>();

            var propertiesReqd = AttributeLists<MatrixItem>.PropertyMapConstraint
                ._Where(d => d.Value == eConstraint.Required)._Select(d => d.Key);

            foreach (PropertyInfo prop in NewItem.GetType().GetProperties())
            {
                if (propertiesReqd._Contains(prop.Name))
                    if (Convert.ToString(prop.GetValue(NewItem, null)).IsBlank())
                    { if (result) result = false; faults.Add(prop.Name); }
            }

            string delim = "\n    * ";
            if (faults.Count > 0) sFaultFields = delim + faults.AppendText(delim);

            return result;
        }

        private void ClearNewItemFields(MatrixItem newItem)
        {
            if (!newItem.IsNull())
            {
                switch (UpdateMode)
                {
                    case eUpdateMode.Edit:
                        {
                            NewItem = (MatrixItem)newItem.SerializeToFormattedData(eSerializationFormat.Xml)
                                .DeSerializeFromFormattedData<MatrixItem>(eSerializationFormat.Xml, false);
                            SelectedGroup = SelectedMatrixItem.MatrixGroup;
                        }
                        break;

                    case eUpdateMode.Add:
                    default:
                        {
                            NewItem = newItem;
                            SelectedGroup = null;
                        }
                        break;
                }
            }
        }
    }
}
